package org.senseframework.support.orm.mybatis.query.builder;

import org.senseframework.support.orm.mybatis.definition.Order;
import org.senseframework.support.orm.mybatis.definition.OrderBy;
import org.senseframework.support.orm.mybatis.definition.Query;
import org.senseframework.support.orm.mybatis.definition.Where;
import org.senseframework.support.orm.mybatis.query.IEntityAsCriteria;
import org.senseframework.support.orm.mybatis.query.IEntityCriteria;

import java.util.ArrayList;
import java.util.Arrays;
import java.util.List;

/**
 * Author lanjian
 * Email  jianlan@iflytek.com
 */
public class QueryBuilder<T extends QueryBuilder> extends BaseQuery implements IEntityCriteria<T>, IEntityAsCriteria<T> {

    public static QueryBuilder build(Class clazz) {
        return new QueryBuilder(clazz);
    }

    protected QueryBuilder(Class clazz) {
        super(clazz);
    }

    public Integer begin() {
        return page * size;
    }

    private Integer size = 10;

    private Integer page = 0;

    public Integer getPage() {
        return page;
    }

    public void setPage(Integer page) {
        this.page = page;
    }

    public Integer getSize() {
        return size;
    }

    public void setSize(Integer size) {
        this.size = size;
    }

    private String sum;


    public String getSum() {
        return sum;
    }

    public QueryBuilder sum(String p) {
        this.sum = p;
        return this;
    }


    public QueryBuilder page(Integer page) {
        this.page = (page == null) ? 0 : page;
        this.page = page < 0 ? 0 : page;
        return this;
    }

    public QueryBuilder size(Integer size) {
        this.size = (size == null) ? 10 : size;
        this.size = (size > 50) ? 50 : size;
        return this;
    }

    protected Integer pageSize() {
        return size;
    }


    private List<Query> queries = new ArrayList<Query>();

    private List<Order> orders = new ArrayList<Order>();

    public List<Query> getQueries() {
        return queries;
    }

    public void setQueries(List<Query> queries) {
        this.queries = queries;
    }

    public List<Order> getOrders() {
        return orders;
    }

    public void setOrders(List<Order> orders) {
        this.orders = orders;
    }

    private void addQuery(Query query) {
        synchronized (this) {
            if (!queries.contains(query)) {
                queries.add(query);

            }
        }
    }


    /**
     * 不等于  <>
     *
     * @param p
     * @param value
     * @return
     */
    public T ne(String p, Object value) {
        addQuery(Where.NE.where(p, p, value));
        return (T) this;
    }

    /**
     * 等于  =
     *
     * @param p
     * @param value
     * @return
     */
    public T eq(String p, Object value) {
        addQuery(Where.EQ.where(p, p, value));
        return (T) this;
    }

    /**
     * 大于  >
     *
     * @param p
     * @param value
     * @return
     */
    public T gt(String p, Object value) {
        addQuery(Where.GT.where(p, p, value));
        return (T) this;
    }

    /**
     * 大于等于 >=
     *
     * @param p
     * @param value
     * @return
     */
    public T ge(String p, Object value) {
        addQuery(Where.GE.where(p, p, value));
        return (T) this;
    }

    /**
     * 小于 <
     *
     * @param p
     * @param value
     * @return
     */
    public T lt(String p, Object value) {
        addQuery(Where.LT.where(p, p, value));
        return (T) this;
    }

    /**
     * 小于等于 <=
     *
     * @param p
     * @param value
     * @return
     */
    public T le(String p, Object value) {
        addQuery(Where.LE.where(p, p, value));
        return (T) this;
    }

    /**
     * like %value%
     *
     * @param p
     * @param value
     * @return
     */
    public T like(String p, Object value) {
        addQuery(Where.LIKE.where(p, p, "%" + value + "%"));
        return (T) this;
    }

    /**
     * like %value
     *
     * @param p
     * @param value
     * @return
     */
    public T likeStart(String p, Object value) {
        addQuery(Where.LIKE.where(p, p, "%" + value));
        return (T) this;
    }

    /**
     * like value%
     *
     * @param p
     * @param value
     * @return
     */
    public T likeEnd(String p, Object value) {
        addQuery(Where.LIKE.where(p, p, value + "%"));
        return (T) this;
    }

    /**
     * is not null
     *
     * @param p
     * @return
     */
    public T isNotNull(String p) {
        addQuery(Where.NOTNULL.whereProperty(p, p));
        return (T) this;
//        throw new RuntimeException("not impl");
    }

    /**
     * is null
     *
     * @param p
     * @return
     */
    public T isNull(String p) {
        addQuery(Where.ISNULL.whereProperty(p, p));
        return (T) this;
//        throw new RuntimeException("not impl");
    }

    /**
     * is not Empty
     *
     * @param p
     * @return
     */
    public T isNotEmpty(String p) {
        addQuery(Where.NOTEMPTY.whereProperty(p, p));
        return (T) this;
//        throw new RuntimeException("not impl");
    }

    /**
     * is Empty
     *
     * @param p
     * @return
     */
    public T isEmpty(String p) {
        addQuery(Where.ISEMPTY.whereProperty(p, p));
        return (T) this;
    }


//    @Override
//    public T between(String p, Object lo, Object hi) {
//        throw new RuntimeException("not impl");
//    }
//
//    @Override
//    public T notBetween(String p, Object lo, Object hi) {
//        throw new RuntimeException("not impl");
//    }

    @Override
    public T in(String p, Object... values) {
        addQuery(Where.IN.where(p, p, Arrays.asList(values)));
        return (T) this;
    }

    @Override
    public T notIn(String p, Object... values) {
        addQuery(Where.NOTIN.where(p, p, Arrays.asList(values)));
        return (T) this;
    }

    @Override
    public T in(String p, List values) {
        addQuery(Where.IN.where(p, p, values));
        return (T) this;
    }

    @Override
    public T notIn(String p, List values) {
        addQuery(Where.NOTIN.where(p, p, values));
        return (T) this;
    }

    /**
     * @param p
     * @return
     */
    public T asc(String p) {
        addOrder(OrderBy.ASC.order(p, null));
        return (T) this;
    }

    private void addOrder(Order order) {
        synchronized (this) {
            if (!orders.contains(order)) {
                orders.add(order);
            }
        }
    }

    /**
     * @param p
     * @return
     */
    public T desc(String p) {
        addOrder(OrderBy.DESC.order(p, null));
        return (T) this;
    }

    @Override
    public T in(String p, String pas, Object... values) {
        addQuery(Where.IN.where(p, pas, Arrays.asList(values)));
        return (T) this;
    }

    @Override
    public T notIn(String p, String pas, Object... values) {
        addQuery(Where.NOTIN.where(p, pas, Arrays.asList(values)));
        return (T) this;
    }

    @Override
    public T in(String p, String pas, List values) {
        addQuery(Where.IN.where(p, pas, values));
        return (T) this;
    }

    @Override
    public T notIn(String p, String pas, List values) {
        addQuery(Where.NOTIN.where(p, pas, values));
        return (T) this;
    }

    @Override
    public T likeEnd(String p, String pas, Object value) {
        addQuery(Where.LIKE.where(p, pas, value + "%"));
        return (T) this;
    }

    @Override
    public T likeStart(String p, String pas, Object value) {
        addQuery(Where.LIKE.where(p, pas, "%" + value));
        return (T) this;
    }

    @Override
    public T like(String p, String pas, Object value) {
        addQuery(Where.LIKE.where(p, pas, "%" + value + "%"));
        return (T) this;
    }

    @Override
    public T lt(String p, String pas, Object value) {
        addQuery(Where.LT.where(p, pas, value));
        return (T) this;
    }

    @Override
    public T le(String p, String pas, Object value) {
        addQuery(Where.LE.where(p, pas, value));
        return (T) this;
    }

    @Override
    public T ge(String p, String pas, Object value) {
        addQuery(Where.GE.where(p, pas, value));
        return (T) this;
    }

    @Override
    public T gt(String p, String pas, Object value) {
        addQuery(Where.GT.where(p, pas, value));
        return (T) this;
    }

    @Override
    public T eq(String p, String pas, Object value) {
        addQuery(Where.EQ.where(p, pas, value));
        return (T) this;
    }

    @Override
    public T ne(String p, String pas, Object value) {
        addQuery(Where.NE.where(p, pas, value));
        return (T) this;
    }
}
